package me.zhengjie.modules.security.service;

import com.alibaba.fastjson2.JSONObject;
import me.zhengjie.domain.Dept;
import me.zhengjie.domain.Role;
import me.zhengjie.domain.User;
import me.zhengjie.dto.DeptDto;
import me.zhengjie.dto.JwtUserDto;
import me.zhengjie.dto.UserDto;
import me.zhengjie.gas.model.ResponseDto;
import me.zhengjie.gas.service.ACEService;
import me.zhengjie.modules.security.config.LoginProperties;
import me.zhengjie.modules.security.config.SecurityProperties;
import me.zhengjie.modules.security.security.TokenProvider;
import me.zhengjie.service.DeptService;
import me.zhengjie.service.UserService;
import me.zhengjie.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class MobileService {

	@Autowired
	TokenProvider tokenProvider;

	@Autowired
	private NamedParameterJdbcTemplate jdbcTemplate;

	@Autowired
	private UserDetailsServiceImpl userDetailsService;

	@Autowired
	private UserService userService;

	@Autowired
	private DeptService deptService;

	@Autowired
	private SecurityProperties properties;

	@Autowired
	private ACEService aceService;

	@Autowired
	private PasswordEncoder passwordEncoder;

	@Autowired
	private LoginProperties loginProperties;

	@Autowired
	private OnlineUserService onlineUserService;

	public ResponseDto mobileLogin(String username, String password, HttpServletRequest request) {
		String sql = "select username from eladmin.sys_user u where u.username =:username and u.password =:password and u.enabled";
		MapSqlParameterSource source = new MapSqlParameterSource();
		source.addValue("username", username);
		source.addValue("password", password);

		List<String> list = jdbcTemplate.queryForList(sql, source, String.class);
		if (CollectionUtils.isEmpty(list)) {
			return new ResponseDto(400, "用户名或密码错误");
		}
		String name = list.get(0);

		// 获取用户信息
		JwtUserDto jwtUser = userDetailsService.loadUserByUsername(name);
		Authentication authentication = new UsernamePasswordAuthenticationToken(jwtUser, null, jwtUser.getAuthorities());
		SecurityContextHolder.getContext().setAuthentication(authentication);
		// 生成令牌
		String token = tokenProvider.createToken(jwtUser);

		// 返回 token 与 用户信息
		UserDto user = userService.findByName(name);
		Map<String, Object> authInfo = new HashMap<String, Object>(2) {{
			put("token", token);
			put("user", jwtUser);
			put("name", name);
			put("displayName", user.getNickName());
			put("isRoot", user.getIsAdmin());
			put("deptId", user.getDept().getId());
			put("id", user.getId());
		}};

		if (loginProperties.isSingleLogin()) {
			// 踢掉之前已经登录的token
			onlineUserService.kickOutForUsername(user.getUsername());
		}
		// 保存在线信息
		onlineUserService.save(jwtUser, token, request);

		return new ResponseDto(0, "登录成功", authInfo);
	}

	public ResponseDto generateMobileAccount(Long deptId) {
		Long userId = SecurityUtils.getCurrentUserId();
		UserDto user = userService.findById(userId);
		DeptDto deptDto = deptService.findById(user.getDept().getId());

		List<Long> deptIds = new ArrayList<>();
		deptIds.add(deptDto.getId());
		if (deptDto.getChildren() != null) {
			List<Long> list = deptDto.getChildren().stream().map(DeptDto::getId).collect(Collectors.toList());
			deptIds.addAll(list);
		}
		if (!deptIds.contains(deptId)) {
			return new ResponseDto(400, "No permission");
		}

		String sql = "select user_id from eladmin.sys_user where dept_id =:deptId and enabled and nick_name='mobile'";
		MapSqlParameterSource source = new MapSqlParameterSource();
		source.addValue("deptId", deptId);
		List<Long> list = jdbcTemplate.queryForList(sql, source, Long.class);
		if (!CollectionUtils.isEmpty(list)) {
			userId = list.get(0);
			UserDto userDto = userService.findById(userId);
			String encrypted = genMobileEncryptedText(userDto.getUsername(), userDto.getPassword(), deptIds);
			return new ResponseDto(0, "success", Map.of("encrypted", encrypted));
		}


		User mobileUser = new User();
		mobileUser.setUsername("mobile" + deptId);
		mobileUser.setNickName("mobile");
		mobileUser.setGender("男");
		Set<Role> roles = new HashSet<>();
		Role role = new Role();
		role.setId(2L);
		roles.add(role);
		mobileUser.setRoles(roles);

		Dept dept = new Dept();
		dept.setId(deptId);
		mobileUser.setDept(dept);
		String password = passwordEncoder.encode("mobile123!");
		mobileUser.setPassword(password);
		mobileUser.setEnabled(true);

		userService.create(mobileUser);

		String encrypted = genMobileEncryptedText(mobileUser.getUsername(), mobileUser.getPassword(), deptIds);
		return new ResponseDto(0, "success", Map.of("encrypted", encrypted));
	}

	private String genMobileEncryptedText(String username, String password, List<Long> deptIds) {
		JSONObject result = new JSONObject();
		result.put("password", password);
		result.put("userName", username);
		result.put("time", LocalDateTime.now());
		result.put("mqttServer", "47.112.140.87");
		result.put("mqttUser", "gasclient");
		result.put("mqttPassword", "1q2w3e4r5t!");
		result.put("deptIds", deptIds);
		String text = result.toString();
		String encrypted = aceService.encrypt(text);

		return encrypted;
	}
}
